/**
 * @addtogroup ofc_string_list.h
 * strings.h
 * @{
 */

/**
 * @file ofc_string_list.h
 * @brief 字符串列表 
 * @note 
 * @author Leo

 * @par          修改日志
 * <table>
 * <tr><th>Date<th>Version<th>Author<th>Description
 * <tr><td>2021-7-21<td>1.0<td>Leo<td>创建初始版本
 * @copyright 杭州鸿泉物联网技术股份有限公司
 */

#ifndef _OFC_STRING_LIST_H_
#define _OFC_STRING_LIST_H_

#include "ofc_string.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct TOfStringItemTag TOfStringItem;
struct TOfStringItemTag
{
    TOfString *string;
    TOfObject *object;
};

/**
 * 字符串列表类.
 * 字符串列表的每一项由字符串TString和对象指针Object组成.
 *
 * @par 示例  
 * @code
   TOfStringList lines;
   TOfStringListCreate(&lines);

   TOfStringListAdd(&lines, "good");
   // ...

   OfDestroyObject((TOfObject *)&lines);
 * @endcode
 */

typedef struct TOfStringListTag TOfStringList;

/**
 * 字符串列表的内容发生改变后触发的事件. 
 * @note: 事件仅在update_count_为0时触发. 即调用BeginUpdate后,EndUpdate前是不会触发调用的 
 * @param sender: 产生该事件的对象
 * @param index: 删除字符串所在的索引
 * @return 
 */
typedef void (*TOfStringListOnDelete)(TOfStringList *sender, Int32 index);

/**
 * 排序用的比较函数
 * @param sender: 产生该事件的对象
 * @param item1: 其中一个比较对象
 * @param item2: 另外一个一个比较对象
 * @return 返回比较结果.如果item1比item2大,返回正数, 相等返回0, 否则返回负数
 */
typedef Int32 (*TOfStringListSortCompare)(TOfStringList *sender, TOfStringItem *item1, TOfStringItem *item2);

struct TOfStringListTag
{
PROTECTED
    TOfObject parent_;  ///< 继承的父类
    TOfVirtualMethod Destroy_;  ///< 析构函数

PUBLIC
    void *receiver;  ///< 可以存放事件的接收者

    TOfNotifyEvent OnChange;  ///< 字符串列表的内容发生改变后触发的事件. 

    TOfStringListOnDelete OnDelete;  ///< 字符串列表项删除时触发的事件.
PRIVATE
    Int32 update_count_;  ///< 更新次数
    TOfStringItem *list_;  ///< 字符串列表
    Int32 count_;  ///< 总项数
    Int32 capacity_;  ///< 能容纳的总项数
    Bool sorted_;  ///< 是否已经排序
};

/**
 * 字符串列表的构造函数
 * @param self: 对象实例指针
 * @return 
 */
void TOfStringListCreate(TOfStringList *self);

/**
 * 创建TOfStringList对象
 * @return 返回TOfStringList对象实例;对象需要通过OfFreeObject释放
 */
TOfStringList *OfCreateStringList(void);

/**
 * 添加一个字符串到列表
 * @param self: 对象实例指针
 * @param s: 添加的字符串
 * @return 添加的字符串在列表中的索引
 */
Int32 TOfStringListAdd(TOfStringList *self, const char *s);

/**
 * 在列表末尾添加一个字符串s,对应的object为参数object
 * @param self: 对象实例指针
 * @param s: 添加的字符串.
 * @param object: 新增项的object指针设置为该值.
 * @return 返回新增项的索引
 */
Int32 TOfStringListAddObject(TOfStringList *self, const char *s, TOfObject *object);

/**
 * 把字符串列表strings的所有项(字符串和object)添加到本实例.
 * @param self: 对象实例指针
 * @param strings: 要添加的源字符串列表
 * @return
 */
void TOfStringListAddStrings(TOfStringList *self, const TOfStringList *strings);

/**
 * 把一个TStringList对象source的所有项复制到本实例
 * @param self: 对象实例指针
 * @param source: 要复制的源字符串列表
 * @return
 */
void TOfStringListAssign(TOfStringList *self, const TOfStringList *source);

/**
 * 清除当前字符串列表
 * @param self: 对象实例指针
 * @return 
 */
void TOfStringListClear(TOfStringList *self);

/**
 * 从字符串列表中删除索引为index的这个字符串
 * @param self: 对象实例指针
 * @param index: 需要删除的字符串的索引(从0开始)
 * @return 
 */
void TOfStringListDelete(TOfStringList *self, Int32 index);

/**
 * 字符串列表中索引为index1的项与索引为index2的项交换位置
 * @param self: 对象实例指针
 * @param index1: 交换项1的索引; 如果索引超范围则直接返回
 * @param index2: 交换项2的索引; 如果索引超范围则直接返回
 * @return
 */
void TOfStringListExchange(TOfStringList *self, Int32 index1, Int32 index2);

/**
 * 通过快速查找法查找s在列表中的位置.不区分大小写
 * @note: 列表必须是已排序的
 * @param self: 对象实例指针
 * @param s: 需要查找的字符串
 * @param index: 返回找到项的索引,或者s应该在该列表中的位置
 * @return 返回是否找到与s相等的项
 */
Bool TOfStringListFind(TOfStringList *self, const char *s, Int32 *index);

/**
 * 查找字符串s在列表中的索引,比较时不区分大小写,但必须是整个匹配.
 * @param self: 对象实例指针
 * @param s: 要查找的字符串.
 * @return 返回s在列表中的索引,如果找不到返回-1
 */
Int32 TOfStringListIndexOf(TOfStringList *self, const char *s);

/**
 * 插入一个字符串s到索引为index所在的位置.原先该位置的项向后移动一个.
 * @note: 插入的object为NULL
 * @note: 如果GetSorted(TOfStringList *self, )为True,则插入失败,直接返回
 * @param self: 对象实例指针
 * @param index: 插入位置的索引; 如果index超出范围,则直接返回
 * @param s: 插入的字符串值.
 * @return
 */
void TOfStringListInsert(TOfStringList *self, Int32 index, const char *s); 

/**
 * 对列表按字符串的大小进行快速排序.排序首先以第一个字符大小进行排序,如果相同再按之后的字符进行排序,不区分大小写
 * @param self: 对象实例指针
 * @return
 */
void TOfStringListSort(TOfStringList *self);

/**
 * 用户自定义比较方法的快速排序
 * @note: 如果GetSorted(TOfStringList *self, )返回True,则调用本函数无效,直接返回
 * @param self: 对象实例指针
 * @param compare: 比较的方法
 * @return
 */
void TOfStringListCustomSort(TOfStringList *self, TOfStringListSortCompare compare);

/**
 * 判断当前列表是否已经排序
 * @param self: 对象实例指针
 * @return 已经排序返回True,否则为False
 */
Bool TOfStringListGetSorted(TOfStringList *self);

/**
 * 设置当前列表是否排序.如果为True,则进行排序
 * @param self: 对象实例指针
 * @param value: 是否排序
 * @return
 */
void TOfStringListSetSorted(TOfStringList *self, Bool value);

/**
 * 获取索引为index的这一项的字符串值
 * @param self: 对象实例指针
 * @param index: 要获取项的索引.
 * @return 字符串项的字符串; index超出范围则返回空字符串
 */
TOfString *TOfStringListGet(TOfStringList *self, Int32 index); 

/**
 * 用字符串s替换索引为index的这一项的字符串.
 * @param self: 对象实例指针
 * @param index: 要替换字符串的项.index超出范围则直接返回
 * @param s: 要替换成的值
 * @return
 */
void TOfStringListPut(TOfStringList *self, Int32 index, const char *s);

/**
 * 用object替换索引为index的这一项的object
 * @param self: 对象实例指针
 * @param index: 要替换object的项.index超出范围则直接返回
 * @param object: 要替换成的值
 * @return
 */
void TOfStringListPutObject(TOfStringList *self, Int32 index, TOfObject *object);

/**
 * 返回当前字符串列表的容量
 * @param self: 对象实例指针
 * @return 字符串列表的容量
 */
Int32 TOfStringListCapacity(TOfStringList *self);

/**
 * 返回当前列表的总项数
 * @param self: 对象实例指针
 * @return 总项数
 */
Int32 TOfStringListCount(TOfStringList *self);

/**
 * 返回索引为index的项的object值
 * @param self: 对象实例指针
 * @param index: 项索引
 * @return  返回索引为index的字符串项的object值; 如果索引超出范围则返回NULL
 */
TOfObject *TOfStringListObjects(TOfStringList *self, Int32 index);

/**
 * 把列表中索引为cur_index的项移动到new_index这个位置
 * @param self: 对象实例指针
 * @param cur_index: 要移动项的索引; 如果索引超出范围,则直接返回
 * @param new_index: 移动到的目的索引; 如果索引超出范围,则直接返回
 * @return
 */
void TOfStringListMove(TOfStringList *self, Int32 cur_index, Int32 new_index); 

/**
 * 要对字符串列表作大规模更新时需要调用该函数,防止更新时对外的大规模刷新,影响效率.
 * 比如: 该类的某个派生类的每一项都与屏幕显示的内容对应,如果更新某一项,会在屏幕上也更新.
 * 此时如果要大规模的更新这个字符串列表,则会不停的刷新屏幕,导致屏幕抖动,且更新比较慢
 * 调用此函数后则屏幕不再更新,直到调用EndUpdate后一起更新.
 * @note: 
 *  1. 该函数必须与EndUpdate成对的调用;
 *  2. 该函数可以调用多次,每次调用引用计数加1.首次调用该函数会触发调用SetUpdateState(True)
 * @param self: 对象实例指针
 * @return
 */
void TOfStringListBeginUpdate(TOfStringList *self);

/**
 * 与BeginUpdate配套使用,参见BeginUpdate
 * @note: 每次调用引用计数减1,当引用计数为0时会调用SetUpdateState(False)
 * @param self: 对象实例指针
 * @return
 */
void TOfStringListEndUpdate(TOfStringList *self);

/**
 * 插入一个字符串s到索引为index所在的位置,新项的object值为参数object的值.原先该位置的项向后移动一个.
 * @param self: 对象实例指针
 * @param index: 插入位置的索引; 如果index超出范围,则直接返回
 * @param s: 插入的字符串值.
 * @param object: 插入项的object值
 * @return
 */
void TOfStringListInsertObject(TOfStringList *self, Int32 index, const char *s, TOfObject *object);

#ifdef __cplusplus
}  // extern "C"
#endif

#endif // _OFC_STRING_LIST_H_


/**
 * @}
 */
